package cn.edu.dlmu.cogo.framework.utils;

import cn.edu.dlmu.cogo.framework.context.Environment;
import cn.hutool.core.lang.Console;

import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author yixi
 */
public class CogoClassUtil {

    /**
     * 应用类容器
     */
    private static final Set<Class<?>> CLASS_SET = new HashSet<>();

    /**
     * 应用启动主类
     */
    private static Class<?> mainClass;

    /**
     * 设置主类
     * @param mainClass 主类
     */
    public static void setMainClass(Class<?> mainClass){
        CogoClassUtil.mainClass = mainClass;
    }

    /**
     * 获取主类
     * @return 主类
     */
    public static Class<?> getMainClass() {
        return mainClass;
    }

    /**
     * 判断主类上是否有某注解
     * @param annotationType 特定注解
     * @return 是否有某注解
     */
    public static boolean mainClassWithAnnotation(Class<? extends Annotation> annotationType){
        return mainClass.getAnnotation(annotationType) != null;
    }

    /**
     * 初始化类信息
     * @param classes 所有类的集合
     */
    public static void initialize(Set<Class<?>> classes){
        List<Class<?>> removeClassList = ApplicationContextAwareUtil.getRemoveClassList();
        classes.forEach(clazz -> {
            if (!removeClassList.contains(clazz)) {
                boolean add = CLASS_SET.add(clazz);
                if (add) {
                    Console.log("{} [CogoFramework]扫描到组件[{}]", Environment.getSystemTime(), clazz.getName());
                }
            }
        });
    }

    /**
     * 获取所有类
     * @return 类集合
     */
    public static Set<Class<?>> getClasses(){
        return CLASS_SET;
    }

    /**
     * 获取带有特定注解的类集合
     * @param annotationType 特定注解
     * @return 类集合
     */
    public static Set<Class<?>> getClassesWithAnnotation(Class<? extends Annotation> annotationType){
        return getClassesWithAnnotation(annotationType,true);
    }

    public static Set<Class<?>> getClassesWithAnnotation(Class<? extends Annotation> annotationType, boolean excludeInterface){
        if (excludeInterface) {
            return CLASS_SET.stream()
                    .filter(clazz -> clazz.getAnnotation(annotationType) != null)
                    .filter(clazz -> !clazz.isAnnotation())
                    .filter(clazz -> !clazz.isInterface())
                    .collect(Collectors.toSet());
        }
        return CLASS_SET.stream()
                .filter(clazz -> clazz.getAnnotation(annotationType) != null)
                .collect(Collectors.toSet());
    }

    /**
     * 获取继承、实现特定类或接口的集合（不包含父类或接口）
     * @param extendsClass 父类或接口
     * @return 类集合
     */
    public static Set<Class<?>> getClassesExtendClass(Class<?> extendsClass){
        return CLASS_SET.stream()
                .filter(extendsClass::isAssignableFrom)
                .filter(clazz -> clazz != extendsClass)
                .collect(Collectors.toSet());
    }
}
